﻿SSVC.Wrap.Dojo.SetObject("SSVC.SVG.ActiveElement", function()
{

    function reorderElements(sortingElementsArr)
    {
        for (var i in sortingElementsArr)
        {
            if (i === 0)
                sortingElementsArr[i].toBack();
            else
                sortingElementsArr[i].toFront();
        }
    }

    SSVC.Wrap.Dojo.Declare("ActiveElement", SSVC.SVG.Group,
	{
	    Contour: null,
	    InnerElement: null,
	    Frame: null,
	    SelectMode: null,
	    SelectOptions:
		{
		    None: "none",
		    Selected: "selected",
		    Contoured: "contoured"
		},
	    Tops: null,
	    InnerXml: "",
	    MinSize: 5,

	    selectedTop: null,
	    selectedPoint: null,

	    constructor: function()
	    {
	        this.Tops = [];
	        this._addInnerElement();
	        this._addSelection();
	        this._arrangeGroupNode();

	        this.SelectMode = this.SelectOptions.None;

	        SSVC.Wrap.Dojo.On(this.Node, "mousedown", SSVC.Wrap.Dojo.Partial(this.OnMouseDown, this));

	        SSVC.Wrap.Dojo.On(this.Node, "mouseover", SSVC.Wrap.Dojo.Partial(this.OnMouseOver, this));
	        SSVC.Wrap.Dojo.On(this.Node, "mouseup", SSVC.Wrap.Dojo.Partial(this.OnMouseUp, this));
	    },

	    OnMouseUp: function(callElement)
	    {
	        callElement.Select();
	    },

	    OnTopMouseUp: function(callElement)
	    {
	        callElement.selectedTop = null;
	    },

	    OnTopMouseDown: function(callElement)
	    {
	        callElement.selectedTop = arguments[1];
	    },

	    OnMouseDown: function(callElement)
	    {
	        var offsetX = arguments[1].offsetX === undefined ? arguments[1].layerX : arguments[1].offsetX;
	        var offsetY = arguments[1].offsetY === undefined ? arguments[1].layerY : arguments[1].offsetY;
	        callElement.selectedPoint = { x: offsetX, y: offsetY };
	        
	    },

	    _arrangeInnerElements: function()
	    {
	        this.InnerElement.update(this.X, this.Y, this.OX, this.OY);
	        if (this.Contour != null)
	            this.Contour.update(this.X, this.Y, this.OX, this.OY);
	        reorderElements([this.InnerElement, this.Frame].concat(this.Tops));
	    },

	    _addInnerElement: function()
	    {
	        this.InnerElement = new SSVC.SVG.Rectangle();
	    },

	    _arrangeGroupNode: function()
	    {
	        this.addChild(this.Frame);
	        this.addChild(this.InnerElement);
	        if (this.Contour != null)
	            this.addChild(this.Contour);
	    },

	    _addSelection: function()
	    {
	        this._addSelectionTops();
	        this.Frame = new SSVC.SVG.Rectangle();
	        this.Frame.Class = "Frame";

	        if (this.Contour == null)
	        {
	            this.Contour = SSVC.SVG.Shape.Clone(this.InnerElement);
	            this.Contour.Class = "Contour";
	            this.Contour.ID += "_Contour";
	        }
	    },

	    _addSelectionTops: function()
	    {
	        for (var el in SSVC.SVG.ActiveElement.Enums.ResizingTops)
	        {
	            var top = new SSVC.SVG.Circle();
	            top.Class = "Top";
	            top.Name = el;
	            top.Number = SSVC.SVG.ActiveElement.Enums.ResizingTops[el];

	            SSVC.Wrap.Dojo.On(top.Node, "mousedown", SSVC.Wrap.Dojo.Partial(this.OnTopMouseDown, this, top.Number));
	            SSVC.Wrap.Dojo.On(top.Node, "mouseup", SSVC.Wrap.Dojo.Partial(this.OnTopMouseUp, this));

	            this.Tops.push(top);
	            this.Node.appendChild(top.Node);
	        }
	        this._setCursorAttrForTops();
	    },

	    _setCursorAttrForTops: function()
	    {
	        this.Tops[0].Node.setAttribute("cursor", "nw-resize");
	        this.Tops[1].Node.setAttribute("cursor", "w-resize");
	        this.Tops[2].Node.setAttribute("cursor", "sw-resize");
	        this.Tops[3].Node.setAttribute("cursor", "ne-resize");
	        this.Tops[4].Node.setAttribute("cursor", "e-resize");
	        this.Tops[5].Node.setAttribute("cursor", "se-resize");
	        this.Tops[6].Node.setAttribute("cursor", "n-resize");
	        this.Tops[7].Node.setAttribute("cursor", "s-resize");
	    },

	    _arrangeTops: function()
	    {
	        //todo: temporary cap
	        var topRadius = SSVC.SVG.Shape.GetProperty("top");
	        topRadius = 3;

	        this.Tops[0].update(this.Frame.X, this.Frame.Y, topRadius);
	        this.Tops[1].update(this.Frame.X, this.Frame.Y + this.Frame.OY / 2, topRadius);
	        this.Tops[2].update(this.Frame.X, this.Frame.Y + this.Frame.OY, topRadius);
	        this.Tops[3].update(this.Frame.X + this.Frame.OX, this.Frame.Y, topRadius);
	        this.Tops[4].update(this.Frame.X + this.Frame.OX, this.Frame.Y + this.Frame.OY / 2, topRadius);
	        this.Tops[5].update(this.Frame.X + this.Frame.OX, this.Frame.Y + this.Frame.OY, topRadius);
	        this.Tops[6].update(this.Frame.X + this.Frame.OX / 2, this.Frame.Y, topRadius);
	        this.Tops[7].update(this.Frame.X + this.Frame.OX / 2, this.Frame.Y + this.Frame.OY, topRadius);
	    },

	    _showContour: function()
	    {
	        this.Contour.Visible = true;
	    },

	    _hideContour: function()
	    {
	        this.Contour.Visible = false;
	    },

	    _showTops: function()
	    {
	        this._arrangeTops();
	        for (var el in this.Tops)
	        {
	            this.Tops[el].Visible = true;
	        }
	    },

	    _hideTops: function()
	    {
	        for (var el in this.Tops)
	        {
	            this.Tops[el].Visible = false;
	        }
	    },

	    _showSelection: function()
	    {
	        this.Frame.Transparent = false;
	        this._showTops();
	    },

	    _hideSelection: function()
	    {
	        this.Frame.Transparent = true;
	        this._hideTops();
	    },

	    _showInnerElement: function()
	    {
	        this.InnerElement.Visible = true;
	        this._setInnerXml();
	    },

	    _hideInnerElement: function()
	    {
	        this.InnerElement.Visible = false;
	    },

	    _refreshSelection: function()
	    {
	        var lineWidth = (this.InnerElement.LineWidth) ? this.InnerElement.LineWidth : 2;
	        this.Frame.update(this.X - lineWidth, this.Y - lineWidth, this.OX + lineWidth * 2, this.OY + lineWidth * 2);
	        switch (this.SelectMode)
	        {
	            case this.SelectOptions.Contoured:
	                this._showContour();
	                this._hideInnerElement();
	                this._hideSelection();
	                break;
	            case this.SelectOptions.Selected:
	                this._showSelection();
	                this._showInnerElement();
	                this._hideContour();
	                break;
	            case this.SelectOptions.None:
	                this._hideContour();
	                this._hideSelection();
	                this._showInnerElement();
	                break;
	        }
	    },

	    _move: function(x, y, selectedPoint)
	    {
	        if (!this.selectedPoint) return;

	        var deltaX = x - this.selectedPoint.x;
	        var deltaY = y - this.selectedPoint.y;

	        this.selectedPoint.x = x;
	        this.selectedPoint.y = y;

	        this.X += deltaX;
	        this.Y += deltaY;

	        this.SelectMode = this.SelectOptions.Contoured;
	    },

	    _resize: function(x, y, shiftKey)
	    {
	        function setValuesForLeft()
	        {
	            var currX = newx;
	            newx = x;
	            var diff = currX - x;
	            if (shiftKey)
	                diff = diff * 2;
	            newox += diff;
	        }
	        function setValuesForRight()
	        {
	            var currX = newx + newox;
	            var diff = currX - x;
	            if (shiftKey)
	            {
	                newx += diff;
	                diff = diff * 2;
	            }
	            newox -= diff;
	        }
	        function setValuesForTop()
	        {
	            var currY = newy;
	            newy = y;
	            var diff = currY - y;
	            if (shiftKey)
	                diff = diff * 2;
	            newoy += diff;
	        }
	        function setValuesForBottom()
	        {
	            var currY = newy + newoy;
	            var diff = currY - y;
	            if (shiftKey)
	            {
	                newy += diff;
	                diff = diff * 2;
	            }
	            newoy -= diff;
	        }

	        if (!this.selectedTop) return;

	        var newx = this.X,
                newy = this.Y,
                newox = this.OX,
                newoy = this.OY;
	        switch (this.selectedTop)
	        {
	            case SSVC.SVG.ActiveElement.Enums.ResizingSides.LEFT:
	                setValuesForLeft();
	                break;
	            case SSVC.SVG.ActiveElement.Enums.ResizingSides.RIGHT:
	                setValuesForRight();
	                break;
	            case SSVC.SVG.ActiveElement.Enums.ResizingSides.TOP:
	                setValuesForTop();
	                break;
	            case SSVC.SVG.ActiveElement.Enums.ResizingSides.BOTTOM:
	                setValuesForBottom();
	                break;
	            case SSVC.SVG.ActiveElement.Enums.ResizingSides.LEFT_TOP:
	                setValuesForLeft();
	                setValuesForTop();
	                break;
	            case SSVC.SVG.ActiveElement.Enums.ResizingSides.LEFT_BOTTOM:
	                setValuesForLeft();
	                setValuesForBottom();
	                break;
	            case SSVC.SVG.ActiveElement.Enums.ResizingSides.RIGHT_TOP:
	                setValuesForRight();
	                setValuesForTop();
	                break;
	            case SSVC.SVG.ActiveElement.Enums.ResizingSides.RIGHT_BOTTOM:
	                setValuesForRight();
	                setValuesForBottom();
	                break;
	        }

	        if (newox <= this.MinSize || newoy <= this.MinSize) return;
	        this.update(newx, newy, newox, newoy);
	    },

	    _getTopByNumber: function(number)
	    {
	        for (var i in this.Tops)
	        {
	            if (this.Tops[i].Number == number)
	                return this.Tops[i];
	        }
	        return null;
	    },

	    _getRectSpace: function(startX, startY, currX, currY)
	    {
	        var ox = currX - startX;
	        var oy = currY - startY;
	        var x, y, side;

	        if (ox < 0 && oy < 0)
	        {
	            ox = Math.abs(ox);
	            oy = Math.abs(oy);
	            x = startX - ox;
	            y = startY - oy;
	            side = 3;
	        }
	        else if (ox < 0 && oy >= 0)
	        {
	            ox = Math.abs(ox);
	            x = startX - ox;
	            y = startY;
	            side = 4;
	        }
	        else if (ox >= 0 && oy < 0)
	        {
	            oy = Math.abs(oy);
	            x = startX;
	            y = startY - oy;
	            side = 2;
	        }
	        else
	        {
	            x = startX;
	            y = startY;
	            side = 1;
	        }

	        return { x: x, y: y, ox: ox, oy: oy, side: side };
	    },

	    _setInnerXml: function()
	    {
	        this.InnerXml = this.InnerElement.getXml().xml;
	    },

	    toFront: function()
	    {
	        this.Node.ownerSVGElement.appendChild(this.Node);
	    },

	    toBack: function()
	    {
	        this.Node.ownerSVGElement.appendChild(this.Node, this.Node.ownerSVGElement.firstChild);
	    },

	    GetOuterXml: function()
	    {
	        return this.InnerElement.getXml();
	    },

	    restoreCoo: function(xmlNode) // override for any shape
	    {
	        this.X = +xmlNode.getAttribute(this.InnerElement.axis.x);
	        this.Y = +xmlNode.getAttribute(this.InnerElement.axis.y);
	        this.OX = +xmlNode.getAttribute(this.InnerElement.axis.ox);
	        this.OY = +xmlNode.getAttribute(this.InnerElement.axis.oy);
	    },

	    SetXml: function(xmldoc)
	    {
	        this.InnerElement.applyXml(xmldoc);
	        this.restoreCoo(xmldoc);
	        this.SelectMode = this.SelectOptions.None;
	        this.Refresh();
	    },

	    Fill: function(rgb)
	    {
	        this.InnerElement.Background = rgb;
	    },

	    SetLineProperties: function(width, color, dash)
	    {
	        this.InnerElement.LineColor = color;
	        this.InnerElement.LineDash = dash;
	        this.InnerElement.LineWidth = width;
	    },

	    AddProperties: function(properties)
	    {
	        this.FontSize = (properties.fontSize) ? properties.fontSize : "";
	        if (properties.strokeWidth)
	            this.SetLineProperties(properties.strokeWidth, properties.lineColor, properties.strokeDash);
	        if (properties.background)
	            this.Fill(properties.background);
	    },

	    Refresh: function()
	    {
	        this.update(this.X, this.Y, this.OX, this.OY);
	        this._arrangeInnerElements();
	        this._refreshSelection();
	    },

	    Move: function(x, y, shiftKey)
	    {
	        if (this.selectedTop == null)
	        {
	            this._move(x, y);
	        }
	        else
	        {
	            this._resize(x, y, shiftKey);
	        }
	        this.Refresh();
	    },

	    Draw: function(startX, startY, currX, currY, shiftKey)
	    {
	        this.SelectMode = this.SelectOptions.Contoured;

	        var rectCoordinates = this._getRectSpace(startX, startY, currX, currY);
	        if (shiftKey)
	        {
	            if (rectCoordinates.ox > rectCoordinates.oy)
	                rectCoordinates.oy = rectCoordinates.ox;
	            else
	                rectCoordinates.ox = rectCoordinates.oy;
	        }

	        this.X = rectCoordinates.x; this.Y = rectCoordinates.y; this.OX = rectCoordinates.ox; this.OY = rectCoordinates.oy;
	        this.Refresh();
	    },

	    Select: function()
	    {
	        this.SelectMode = this.SelectOptions.Selected;
	        this.Refresh();
	    },

	    Deselect: function()
	    {
	        this.SelectMode = this.SelectOptions.None;
	        this.Cursor = SSVC.SVG.ActiveElement.Enums.Cursors.Default;
	        this.Refresh();
	    },

	    ScaleX: function(factor)
	    {
	        if (factor <= 0)
	            return;

	        this.X *= factor;
	        this.OX *= factor;
	        this.Refresh();
	    },

	    ScaleY: function(factor)
	    {
	        if (factor <= 0)
	            return;

	        this.Y *= factor;
	        this.OY *= factor;
	        this.Refresh();
	    },

	    Delete: function()
	    {
	        this.Node.parentNode.removeChild(this.Node);
	    }
	});

    ActiveElement.XmlDeserialize = function(xmlDoc)
    {
        var obj = SSVC.SVG.ActiveElement.CreateElementByTag(xmlDoc.nodeName, xmlDoc.getAttribute("complextype"));
        obj.SetXml(xmlDoc);
        //obj.Refresh();
        return obj;
    };

    ActiveElement.CreateElementByTag = function(tagName, complextype)
    {
        switch (tagName)
        {
            case SSVC.SVG.ActiveElement.Enums.ElementType.ELLIPSE:
                return new SSVC.SVG.ActiveEllipseElement();
            case SSVC.SVG.ActiveElement.Enums.ElementType.LINE:
                return new SSVC.SVG.ActiveLineElement();
            case SSVC.SVG.ActiveElement.Enums.ElementType.SCRIBBLE:
                return new SSVC.SVG.ActiveScribbleElement();
            case SSVC.SVG.ActiveElement.Enums.ElementType.COMPLEX:
                if (complextype == SSVC.SVG.ActiveElement.Enums.ElementType.LABEL)
                    return new SSVC.SVG.ActiveLabelElement();
                break;
            default:
                return new SSVC.SVG.ActiveElement();
        }
    };

    ActiveElement.Enums =
{
    // Selected area tops:
    //  1........7........4
    //  .                 .
    //  .                 .
    //  2                 5
    //  .                 .
    //  .                 .
    //  3........8........6  

    ResizingSides:
    {
        LEFT: +2,
        RIGHT: +5,
        TOP: +7,
        BOTTOM: +8,
        LEFT_TOP: +1,
        RIGHT_TOP: +4,
        LEFT_BOTTOM: +3,
        RIGHT_BOTTOM: +6
    },

    ElementType:
    {
        ELLIPSE: "ellipse",
        RECT: "rect",
        LINE: "line",
        LABEL: "label",
        SCRIBBLE: "polyline",
        COMPLEX: "g"
    },
    ElementAxis:
    {
        ForLine: { x: "x1", y: "y1", ox: "x2", oy: "y2" },
        ForRectangle: { x: "x", y: "y", ox: "width", oy: "height" },
        ForEllipse: { x: "cx", y: "cy", ox: "rx", oy: "ry" },
        ForCircle: { x: "cx", y: "cy", ox: "r", oy: "r" },
        ForText: { x: "x", y: "y", ox: "width", oy: "height" },
        ForMarker: { x: "refX", y: "refY", ox: "markerWidth", oy: "markerHeight" }
    },
    ResizingTops:
    {
        TopLeft: 1,
        MiddleLeft: 2,
        BottomLeft: 3,
        TopRight: 4,
        MiddleRight: 5,
        BottomRight: 6,
        TopMiddle: 7,
        BottomMiddle: 8,
    },

    SelectMode:
        {
            None: 0, Selected: 1, Contoured: 2
        },
    Cursors:
        {
            Move: "move",
            Default: "default"
        }
};

    return ActiveElement;
}());
